//go:build windows

package pcmemory

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/StackExchange/wmi"
	"github.com/urfave/cli/v2"
	"os"
)

var (
	BuildTime string
	Version   = "1.0.0"
)

func Do() {
	app := &cli.App{
		Name:        "memory",
		Version:     fmt.Sprintf("%s build:%s", Version, BuildTime),
		UsageText:   "eg: memory s ",
		Description: "通过 wmi 获取内存信息",
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:     "serial",
				Category: "获取序列号,结果为json数组",
				Value:    true,
				Aliases:  []string{"s"},
				Action: func(ctx *cli.Context, b bool) error {
					d, err := GetMemoryInfo()
					if err != nil {
						return err
					}
					str := make([]string, len(d))
					for k, v := range d {
						str[k] = v.SerialNumber
					}
					bs, err := json.Marshal(str)
					if err != nil {
						return err
					}
					w := bufio.NewWriter(os.Stdout)
					w.WriteString(string(bs) + "\n")
					w.Flush()
					return nil
				},
			},
		},

		Action: func(ctx *cli.Context) error {
			if !ctx.IsSet("serial") {
				d, err := GetMemoryInfo()
				if err != nil {
					return cli.Exit("获取内存信息时发生错误", 1)
				}
				bs, err := json.Marshal(d)
				if err != nil {
					return cli.Exit("数据转换为json字符串时发生错误", 1)
				}
				w := bufio.NewWriter(os.Stdout)
				w.WriteString(string(bs) + "\n")
				w.Flush()
			}
			return nil
		},
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Printf("命令行调用错误：%s ，请查看帮助文档", err.Error())
	}
}

type MemoryBaseInfo struct {
	Capacity             uint64 // eg:8589934592 ，获取内存容量, / 1024*1024*1024 才能换算成GB
	Description          string // eg:物理内存 ，物理内存还虚拟内存
	ConfiguredClockSpeed uint32 //eg；2133 (0x855) ，配置时钟速度
	ConfiguredVoltage    uint32 // eg：1200 (0x4B0) ，配置电压
	DataWidth            uint16 // eg：64，获取内存数据带宽
	Manufacturer         string // eg：859B，生产商
	MaxVoltage           uint32 // eg：1200 ，最大电压
	MinVoltage           uint32 // eg：1200 ，最小电压
	Model                string // eg：null ，型号 // 不清楚是我电脑的问题还是其他什么原因
	PartNumber           string // eg：CT8G4DFS8266.M8FE   ，零件编号,由生产商定义
	SerialNumber         string // eg：2271E66A，编号
	SKU                  string // eg：null，SKU号 // 不清楚是我电脑的问题还是其他什么原因
	Speed                uint32 // eg：2667，速率 内存频率 单位MHz
	Tag                  string // eg：Physical Memory 0，唯一标识符的物理存储器
}

// GetMemoryInfo 获取 内存信息
func GetMemoryInfo() (data []MemoryBaseInfo, err error) {
	err = wmi.Query("SELECT * FROM Win32_PhysicalMemory", &data)
	if err != nil {
		return nil, err
	}
	return data, nil
}
